﻿//---------------------------------------------------------------------------------
// Copyright (c) 2013, Microsoft Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//---------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Microsoft.Azure.E2E.Common.Tests
{
    [TestClass]
    [ExcludeFromCodeCoverage]
    public class TypeSafeConstantBaseTests
    {
        [TestMethod]
        public void Test_BooBarBaz_Parse_NoPreInit()
        {
            Assert.IsNotNull(TestConstants.Parse("Foo"));
        }

        [TestMethod]
        public void Test_TestConstants_Cast_InRange()
        {
            Assert.AreEqual(TestConstants.Foo, (TestConstants)"Foo1");
            Assert.AreNotEqual(TestConstants.Baz, (TestConstants)"Foo1");
            Assert.AreEqual(TestConstants.Bar, (TestConstants)"Bar2");
        }

        [TestMethod]
        public void Test_TestConstants_CastToUnderlyingType()
        {
            Assert.AreEqual("Bar2", (string)TestConstants.Bar);
        }

        [TestMethod]
        public void Test_TestConstants_Equals()
        {
            Assert.IsTrue(TestConstants.Foo.Equals(TestConstants.Foo));
            Assert.IsFalse(TestConstants.Bar.Equals(TestConstants.Foo));

            Assert.IsTrue(TestConstants.Foo.Equals((object)TestConstants.Foo));
            Assert.IsFalse(TestConstants.Foo.Equals((object)null));
            // ReSharper disable once SuspiciousTypeConversion.Global
            Assert.IsTrue(TestConstants.Foo.Equals((object)"Foo1"));

            Assert.IsTrue(TestConstants.Foo.Equals("Foo1"));
            Assert.IsFalse(TestConstants.Foo.Equals("Bar2"));
        }

        [TestMethod]
        public void Test_TestConstants_Equals_Null()
        {
            Assert.AreNotEqual(null, TestConstants.Baz);
        }

        [TestMethod]
        public void Test_TestConstants_GetHashCode()
        {
            Assert.AreEqual("Bar2".GetHashCode(), TestConstants.Bar.GetHashCode());
        }

        [TestMethod]
        public void Test_TestConstants_MemberNames()
        {
            var names = new HashSet<string>(TestConstants.Names);
            Assert.AreEqual(3, names.Count);
            var expectedNames = new HashSet<string> { "Foo", "Bar", "Baz" };
            names.IntersectWith(expectedNames);
            Assert.AreEqual(3, names.Count);
        }

        [TestMethod]
        [ExpectedException(typeof(KeyNotFoundException))]
        public void Test_TestConstants_Parse_BadProperty()
        {
            TestConstants.Parse("Chickens!");
        }

        [TestMethod]
        public void Test_TestConstants_Parse_Successful()
        {
            Assert.AreEqual(TestConstants.Foo, TestConstants.Parse("Foo"));
            Assert.AreNotEqual(TestConstants.Foo, TestConstants.Parse("Bar"));
        }

        [TestMethod]
        public void Test_TestConstants_ToString()
        {
            Assert.AreEqual("Foo", TestConstants.Foo.ToString());
            Assert.AreEqual("(Unknown)", TestConstants.CloseButNotReadOnly.ToString());
        }

        [TestMethod]
        public void Test_TestConstants_TryParse()
        {
            TestConstants result;
            Assert.IsTrue(TestConstants.TryParse("Foo", out result));
            Assert.AreEqual(TestConstants.Foo, result);

            Assert.IsFalse(TestConstants.TryParse("Woof", out result));
            Assert.IsNull(result);
        }

        [TestMethod]
        public void Test_TestConstants_Values()
        {
            var values = new HashSet<string>(TestConstants.Values);
            Assert.AreEqual(3, values.Count);
            var expectedValues = new HashSet<string> { "Foo1", "Bar2", "Baz3" };
            values.IntersectWith(expectedValues);
            Assert.AreEqual(3, values.Count);
        }

        [TestMethod]
        public void Test_WithNull_Equals_Null()
        {
            Assert.AreEqual(TestConstantsWithNullMember.Null, (TestConstantsWithNullMember)(string)null);
        }

        [TestMethod]
        public void Test_TestConstants_Cast_Null()
        {
            Assert.IsNotNull((TestConstants)(string)null);
        }

        [TestMethod]
        public void Test_WithNull_Cast_NonExistent()
        {
            Assert.AreNotEqual(TestConstantsWithNullMember.NotNull, (TestConstantsWithNullMember)"Hi");
            Assert.IsNotNull((TestConstantsWithNullMember)"Hi");
        }

        [TestMethod]
        public void Test_TestConstants_EqualsOperator()
        {
            Assert.IsTrue(TestConstantsWithNullMember.Null == (TestConstantsWithNullMember)(string)null);
            Assert.IsFalse((TestConstantsWithNullMember)null == TestConstantsWithNullMember.Null);
            // ReSharper disable once EqualExpressionComparison
            Assert.IsTrue((TestConstantsWithNullMember)"TestTest" == (TestConstantsWithNullMember)"TestTest");
            Assert.IsTrue(TestConstantsWithNullMember.Null != TestConstantsWithNullMember.NotNull);
            Assert.IsTrue((TestConstantsWithNullMember)"TestTest" != (TestConstantsWithNullMember)"TestTest1");
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void Test_TestConstantsWithNoAdHocConstruction_AdHocConstruction()
        {
            var result = (TestConstantsWithNoAdHocConstruction) "3";
        }
    }
}
